package top.truehaku.generator.code.application.service.impl;

import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import top.truehaku.generator.code.application.service.CodeApplicationService;
import top.truehaku.generator.code.application.assembler.CodeAssembler;
import top.truehaku.generator.code.application.command.CodeGroup;
import top.truehaku.generator.code.application.vo.Variable;
import top.truehaku.generator.code.domain.model.code.*;
import top.truehaku.generator.code.domain.model.table.Table;
import top.truehaku.generator.code.domain.model.table.TableId;
import top.truehaku.generator.code.repository.TableRepository;
import top.truehaku.generator.common.util.JdbcHelper;
import top.truehaku.generator.common.util.ReflectUtils;
import top.truehaku.generator.starter.DataSourceProperties;
import top.truehaku.generator.starter.GlobalCodeProperties;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class CodeApplicationServiceImpl implements CodeApplicationService {

    @Resource(name = "freemarker-configuration")
    private Configuration configuration;
    @Autowired
    private TableRepository tableRepository;
    @Autowired
    private DataSourceProperties dataSourceProperties;
    @Autowired
    private GlobalCodeProperties globalCodeProperties;


    @Override
    public void generator(CodeGroup codeGroup) {
        String tableSchema = codeGroup.getTableSchema() == null?JdbcHelper.getTableSchema(dataSourceProperties.getUrl()):codeGroup.getTableSchema();
        Table table = tableRepository.findById(new TableId(tableSchema, codeGroup.getTableName()));
        table.removePrefixes(globalCodeProperties.getNegligiblePrefixes());
        List<Code> codes = CodeAssembler.toCode(codeGroup, globalCodeProperties, table.getEntityName());
        if (codeGroup.getBaseEntity()!=null){
            Field[] fields = ReflectUtils.getFields(codeGroup.getBaseEntity());
            List<String> parentFields = Arrays.stream(fields).map(Field::getName).collect(Collectors.toList());
            table.getColumnList().forEach(column -> column.setParentIncluded(parentFields));
        }
        codes.forEach(code -> {
            try {
                File target = new File(code.getPath());
                if (target.exists()&&!code.getCodeProperty().isOverridable()){
                    return;
                }
                Template template = configuration.getTemplate(code.getCodeTemplate().getTemplatePath(), "UTF-8");
                File directory = new File(code.getDirectory().getDirectory());
                if (!directory.exists()){
                    directory.mkdirs();
                }
                FileWriter out = new FileWriter(code.getPath());
                Variable variable = CodeAssembler.variableMapping(code, table);
                template.process(variable, out);
            } catch (IOException e) {
                e.printStackTrace();
                throw new RuntimeException("找不到模板");
            } catch (TemplateException e){
                throw new RuntimeException("渲染模板失败");
            }
        });

    }

}
